package com.javacoo.fastdfs.client.internal.client;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.DownloadCallback;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.ProtoCommon;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.UploadCallback;

import com.javacoo.fastdfs.client.api.client.FastDFSClient;
import com.javacoo.fastdfs.client.api.template.FastDFSTemplate;
import com.javacoo.fastdfs.client.exception.JccfcFastDFSException;

import lombok.extern.slf4j.Slf4j;

/**
 * FastDFSClient默认实现类
 * <p>说明:</p>
 * <li>基于org.csource.fastdfs.StorageClient1 1.27.0.0</li>
 *
 * @author duanyong@jccfc.com
 * @date 2020/5/1 23:14
 */
@Slf4j
public class DefaultFastDFSClient implements FastDFSClient {
    /** 协议*/
    private static final String PROTOCOL = "http://";
    /** 分隔符*/
    private static final String SEPAPATOR = "/";
    /** fastDFSTemplate*/
    private FastDFSTemplate fastDFSTemplate;

    /**
     * 初始化
     * <p>说明:</p>
     * <li></li>
     *
     * @param fastDFSTemplate FastDFS操作模板接口
     * @author duanyong@jccfc.com
     * @date 2020/5/3 15:55
     */
    @Override
    public FastDFSClient init(FastDFSTemplate fastDFSTemplate) {
        this.fastDFSTemplate = fastDFSTemplate;
        return this;
    }

    /**
     * 上传文件到存储服务器(按文件名)
     *
     * @param localFileName 待上传的本地文件名称
     * @param fileExtName   文件类型名称，不包含点(.)，如果为空则从localFileName提取
     * @param metaList      元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String localFileName, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(localFileName,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按文件名)
     *
     * @param groupName     要上传文件的组名，可以为空
     * @param localFileName 待上传的本地文件名称
     * @param fileExtName   文件类型名称，不包含点(.)，如果为空则从localFileName提取
     * @param metaList      元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String groupName, String localFileName, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(groupName,localFileName,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按文件字节数组)
     *
     * @param fileBuff    文件内容字节数组
     * @param fileExtName 文件扩展名，不包含(.)
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(byte[] fileBuff, String fileExtName) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(fileBuff,fileExtName,null)));
    }

    /**
     * 上传文件到存储服务器(按文件字节数组)
     *
     * @param fileBuff    文件内容字节数组
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaMap     元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(byte[] fileBuff, String fileExtName, Map<String, String> metaMap) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> {
            NameValuePair[] valuePairs = null;
            if (metaMap != null && !metaMap.isEmpty()) {
                valuePairs = new NameValuePair[metaMap.size()];
                int index = 0;
                for (Map.Entry<String, String> entry : metaMap.entrySet()) {
                    valuePairs[index] = new NameValuePair(entry.getKey(), entry.getValue());
                    index++;
                }
            }
            return Optional.ofNullable(storageClient.upload_file1(fileBuff,fileExtName,valuePairs));
        });
    }

    /**
     * 上传文件到存储服务器(按文件字节数组)
     *
     * @param fileBuff    文件内容字节数组
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaList    元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(byte[] fileBuff, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(fileBuff,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按文件字节数组)
     *
     * @param groupName   要上传文件的组名，可以为空
     * @param fileBuff    文件内容字节数组
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaList    元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String groupName, byte[] fileBuff, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(groupName,fileBuff,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按回调)
     *
     * @param groupName   要上传文件的组名，可以为空
     * @param fileSize    文件大小
     * @param callback    写数据回调对象
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaList    元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String groupName, long fileSize, UploadCallback callback, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(groupName,fileSize,callback,fileExtName,metaList)));
    }

    /**
     * 上传附加文件到存储服务器(按文件名)
     *
     * @param localFileName 待上传的本地文件名称
     * @param fileExtName   文件类型名称，不包含点(.)，如果为空则从localFileName提取
     * @param metaList      元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadAppenderFile(String localFileName, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_appender_file1(localFileName,fileExtName,metaList)));
    }

    /**
     * 上传附加文件到存储服务器(按文件名)
     *
     * @param groupName     要上传文件的组名，可以为空
     * @param localFileName 待上传的本地文件名称
     * @param fileExtName   文件类型名称，不包含点(.)，如果为空则从localFileName提取
     * @param metaList      元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadAppenderFile(String groupName, String localFileName, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_appender_file1(groupName,localFileName,fileExtName,metaList)));
    }

    /**
     * 上传附加文件到存储服务器(按文件字节数组)
     *
     * @param fileBuff    文件内容字节数组
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaList    元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadAppenderFile(byte[] fileBuff, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_appender_file1(fileBuff,fileExtName,metaList)));
    }

    /**
     * 上传附加文件到存储服务器(按文件字节数组)
     *
     * @param groupName   要上传文件的组名，可以为空
     * @param fileBuff    文件内容字节数组
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaList    元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadAppenderFile(String groupName, byte[] fileBuff, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_appender_file1(groupName,fileBuff,fileExtName,metaList)));
    }

    /**
     * 上传附加文件到存储服务器(通过回调)
     *
     * @param groupName   要上传文件的组名，可以为空
     * @param fileSize    文件大小
     * @param callback    写数据回调对象
     * @param fileExtName 文件扩展名，不包含(.)
     * @param metaList    元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadAppenderFile(String groupName, long fileSize, UploadCallback callback, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_appender_file1(groupName,fileSize,callback,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按文件名，从文件)
     *
     * @param masterFileId  文件id来生成从文件
     * @param prefixName    用来生成从属文件的前缀名
     * @param localFileName 待上传的本地文件名称
     * @param fileExtName   文件类型名称，不包含点(.)，如果为空则从localFileName提取
     * @param metaList      元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String masterFileId, String prefixName, String localFileName, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(masterFileId,prefixName,localFileName,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按文件增益，从文件)
     *
     * @param masterFileId 主文件id来生成从文件
     * @param prefixName   用来生成从属文件的前缀名
     * @param fileBuff     文件内容字节数组
     * @param fileExtName  文件扩展名，不包含(.)
     * @param metaList     元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String masterFileId, String prefixName, byte[] fileBuff, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(masterFileId,prefixName,fileBuff,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(按文件增益，从文件)
     *
     * @param masterFileId 主文件id来生成从文件
     * @param prefixName   用来生成从属文件的前缀名
     * @param fileBuff     文件内容字节数组
     * @param offset
     * @param length
     * @param fileExtName  文件扩展名，不包含(.)
     * @param metaList     元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String masterFileId, String prefixName, byte[] fileBuff, int offset, int length, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(masterFileId,prefixName,fileBuff,offset,length,fileExtName,metaList)));
    }

    /**
     * 上传文件到存储服务器(通过回调)
     *
     * @param masterFileId 主文件id来生成从文件
     * @param prefixName   用来生成从属文件的前缀名
     * @param fileSize     文件大小
     * @param callback     写数据回调对象
     * @param fileExtName  文件扩展名，不包含(.)
     * @param metaList     元数据数组
     * @return 如果成功，返回文件id(包括组名和文件名), <br>
     * 失败返回null
     */
    @Override
    public Optional<String> uploadFile(String masterFileId, String prefixName, long fileSize, UploadCallback callback, String fileExtName, NameValuePair[] metaList) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.upload_file1(masterFileId,prefixName,fileSize,callback,fileExtName,metaList)));
    }

    /**
     * 将文件附加到存储服务器(按文件名)
     *
     * @param appenderFileId 附加文件id
     * @param localFileName  要附加的本地文件名
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> appendFile(String appenderFileId, String localFileName) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.append_file1(appenderFileId,localFileName)));
    }

    /**
     * 将文件附加到存储服务器(按文件字节数组)
     *
     * @param appenderFileId 附加文件id
     * @param fileBuff       文件内容字节数组
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> appendFile(String appenderFileId, byte[] fileBuff) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.append_file1(appenderFileId,fileBuff)));
    }

    /**
     * 将文件附加到存储服务器(按文件字节数组)
     *
     * @param appenderFileId 附加文件id
     * @param fileBuff       文件内容字节数组er
     * @param offset         缓冲区的起始偏移量
     * @param length         要追加的缓冲区的长度
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> appendFile(String appenderFileId, byte[] fileBuff, int offset, int length) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.append_file1(appenderFileId,fileBuff,offset,length)));
    }

    /**
     * 将文件追加到存储服务器(通过回调)
     *
     * @param appenderFileId 附加文件id
     * @param fileSize       文件大小
     * @param callback       写数据回调对象
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> appendFile(String appenderFileId, long fileSize, UploadCallback callback) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.append_file1(appenderFileId,fileSize,callback)));
    }

    /**
     * 修改存储服务器的附加文件 (文件名)
     *
     * @param appenderFileId 附加文件id
     * @param fileOffset     附加文件的偏移量
     * @param localFileName  要附加的本地文件名
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> modifyFile(String appenderFileId, long fileOffset, String localFileName) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.modify_file1(appenderFileId,fileOffset,localFileName)));
    }

    /**
     * 修改存储服务器的附加文件 (字节数组)
     *
     * @param appenderFileId 附加文件id
     * @param fileOffset     附加文件的偏移量
     * @param fileBuff       文件内容字节数组
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> modifyFile(String appenderFileId, long fileOffset, byte[] fileBuff) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.modify_file1(appenderFileId,fileOffset,fileBuff)));
    }

    /**
     * 修改存储服务器的附加文件 (字节数组)
     *
     * @param appenderFileId 附加文件id
     * @param fileOffset     附加文件的偏移量
     * @param fileBuff       文件内容字节数组
     * @param bufferOffset   字节数组起始偏移量
     * @param bufferLength   修改的字节数组长度
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> modifyFile(String appenderFileId, long fileOffset, byte[] fileBuff, int bufferOffset, int bufferLength) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.modify_file1(appenderFileId,fileOffset,fileBuff,bufferOffset,bufferLength)));
    }

    /**
     * 修改存储服务器的附加文件 (通过回调)
     *
     * @param appenderFileId 附加文件id
     * @param fileOffset     附加文件的偏移量
     * @param modify_size    修改的大小
     * @param callback       写数据回调对象
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> modifyFile(String appenderFileId, long fileOffset, long modify_size, UploadCallback callback) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.modify_file1(appenderFileId,fileOffset,modify_size,callback)));
    }

    /**
     * 从存储服务器删除文件
     *
     * @param fileId 文件id(包括组名和文件名)
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> deleteFile(String fileId) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.delete_file1(fileId)));
    }

    /**
     * 从存储服务器截断大小为0的追加文件
     *
     * @param appenderFileId 附加文件id
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> truncateFile(String appenderFileId) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.truncate_file1(appenderFileId)));
    }

    /**
     * 从存储服务器截断追加文件
     *
     * @param appenderFileId    附加文件id
     * @param truncatedFileSize 截断文件大小
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> truncateFile(String appenderFileId, long truncatedFileSize) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.truncate_file1(appenderFileId,truncatedFileSize)));
    }

    /**
     * 从存储服务器下载文件
     *
     * @param fileId 文件id(包括组名和文件名)
     * @return 文件内容字节数组er, 失败返回null
     */
    @Override
    public Optional<byte[]> downloadFile(String fileId) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.download_file1(fileId)));
    }

    /**
     * 从存储服务器下载文件
     *
     * @param fileId        文件id(包括组名和文件名)
     * @param fileOffset    文件的开始偏移量
     * @param downloadBytes 下载字节，从偏移量中保留的字节为0
     * @return 文件内容字节数组, 失败返回null
     */
    @Override
    public Optional<byte[]> downloadFile(String fileId, long fileOffset, long downloadBytes) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.download_file1(fileId,fileOffset,downloadBytes)));
    }

    /**
     * 从存储服务器下载文件
     *
     * @param fileId        文件id(包括组名和文件名)
     * @param localFileName 本地的文件名
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> downloadFile(String fileId, String localFileName) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.download_file1(fileId,localFileName)));
    }

    /**
     * 从存储服务器下载文件
     *
     * @param fileId        文件id(包括组名和文件名)
     * @param fileOffset    文件的开始偏移量
     * @param downloadBytes 下载字节，从偏移量中保留的字节为0
     * @param localFileName 本地的文件名
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> downloadFile(String fileId, long fileOffset, long downloadBytes, String localFileName) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.download_file1(fileId,fileOffset,downloadBytes,localFileName)));
    }

    /**
     * 从存储服务器下载文件
     *
     * @param fileId   文件id(包括组名和文件名)
     * @param callback 当数据到达时，回调对象将调用call .recv()
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> downloadFile(String fileId, DownloadCallback callback) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.download_file1(fileId,callback)));
    }

    /**
     * 从存储服务器下载文件
     *
     * @param fileId        文件id(包括组名和文件名)
     * @param fileOffset    文件的开始偏移量
     * @param downloadBytes 下载字节，从偏移量中保留的字节为0
     * @param callback      当数据到达时，回调对象将调用call .recv()
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> downloadFile(String fileId, long fileOffset, long downloadBytes, DownloadCallback callback) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.download_file1(fileId,fileOffset,downloadBytes,callback)));
    }

    /**
     * 从存储服务器获取所有元数据项
     *
     * @param fileId 文件id(包括组名和文件名)
     * @return 元数据数组, 失败返回null
     */
    @Override
    public Optional<NameValuePair[]> getMetadata(String fileId) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.get_metadata1(fileId)));
    }

    /**
     * 设置元数据项
     *
     * @param fileId   文件id(包括组名和文件名)
     * @param metaList 元数据数组
     * @param opFlag   标志，可以是下列值之一: <br>
     *                 <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_OVERWRITE: overwrite,覆盖所有旧的元数据项</li></ul>
     *                 <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_MERGE: merage，当元数据项不存在时插入，否则更新它</li></ul>
     * @return 0表示成功，!= 0表示错误(错误号)
     */
    @Override
    public Optional<Integer> setMetadata(String fileId, NameValuePair[] metaList, byte opFlag) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.set_metadata1(fileId,metaList,opFlag)));
    }

    /**
     * 从存储服务器获取文件信息
     *
     * @param fileId 文件id(包括组名和文件名)
     * @return FileInfo对象为成功，返回null为失败
     */
    @Override
    public Optional<FileInfo> queryFileInfo(String fileId) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.query_file_info1(fileId)));
    }

    /**
     * 从文件名获取文件信息解码
     *
     * @param fileId 文件id(包括组名和文件名)
     * @return FileInfo对象为成功，返回null为失败
     */
    @Override
    public Optional<FileInfo> getFileInfo(String fileId) throws JccfcFastDFSException {
        return fastDFSTemplate.run((StorageClient1 storageClient) -> Optional.ofNullable(storageClient.get_file_info1(fileId)));
    }

    /**
     * 获取文件的绝对地址
     *
     * @param fileId 文件id(包括组名和文件名)
     * @return 成功返回绝对路径，否则返回空
     */
    @Override
    public Optional<String> getFileAbsolutePath(String fileId) throws JccfcFastDFSException {
        //分隔文件名，获取路径
        String[] parts = new String[2];
        byte errno = this.splitFileId(fileId, parts);
        if (errno != 0) {
            return Optional.empty();
        }
        int ts = (int) (System.currentTimeMillis() / 1000), port=80;
        String token = "";
        if (fastDFSTemplate.getFastDFSConfig().isAntiStealToken()) {
            try {
                token = ProtoCommon.getToken(parts[0], ts, fastDFSTemplate.getFastDFSConfig().getSecretKey());
            } catch (Exception e) {
                throw new JccfcFastDFSException(e.getMessage(), e, 0);
            }
            token = "?token=" + token + "&ts=" + ts;
        }
        List<String> addressList;
        if (fastDFSTemplate.getFastDFSConfig().getNginxAddress() != null && fastDFSTemplate.getFastDFSConfig().getNginxAddress().trim() != "") {
            addressList = Arrays.asList(fastDFSTemplate.getFastDFSConfig().getNginxAddress().split(","));
        } else {
            addressList = Arrays.asList(fastDFSTemplate.getFastDFSConfig().getTrackerServers().split(","));
        }

        Random random = new Random();
        int i = random.nextInt(addressList.size());
        String[] split = addressList.get(i).split(":", 2);

        if(fastDFSTemplate.getFastDFSConfig().getTrackerHttpPort() > 0){
            port = fastDFSTemplate.getFastDFSConfig().getTrackerHttpPort();
        }else if (split.length > 1) {
            port = Integer.parseInt(split[1].trim());
        }
        String address = split[0].trim();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(PROTOCOL)
                .append(address)
                .append(":")
                .append(port)
                .append(SEPAPATOR)
                .append(fileId)
                .append(token);
        return Optional.ofNullable(stringBuilder.toString());
    }
     /** 分隔文件ID
     * @author duanyong@jccfc.com
     * @date 2020/4/30 15:13
     * @param fileId: 文件ID
     * @param results:
     * @return: byte
     */
    private byte splitFileId(String fileId, String[] results) {
        int pos = fileId.indexOf(SEPAPATOR);
        if ((pos <= 0) || (pos == fileId.length() - 1)) {
            return ProtoCommon.ERR_NO_EINVAL;
        }
        results[0] = fileId.substring(0, pos); //group name
        results[1] = fileId.substring(pos + 1); //file name
        return 0;
    }
}
